/**
 * 标签页
 */

import Pubsub from '../../helper/Pubsub.js';
import Sha1 from "../../helper/Sha1";
import SequenceDiagrams from "../../markdownRender/SequenceDiagrams";
import Katex from "../../markdownRender/Katex";
import CodeLine from "../../markdownRender/CodeLine";
import Markdown from "../../helper/Markdown";
import State from "../../helper/State";
import Flowchart from "../../markdownRender/Flowchart";
const fs = require('fs');

function isArticle(fileSha1) {
  return fileSha1 !== 'start' && fileSha1 !== 'setting';
}

function isStart(fileSha1) {
  return fileSha1 === 'start';
}

function isSetting(fileSha1) {
  return fileSha1 === 'setting';
}

class Page {
  constructor(wrapper) {
    const _this = this;

    _this.$tabWrapper = wrapper.tab;
    _this.$articleWrapper = wrapper.article;
    _this.$startWrapper = wrapper.start;
    _this.$settingWrapper = wrapper.setting;

    _this.isStartTabExist = false;
    _this.isSettingTabExist = false;

    _this.$tabWrapper.html(
`<div class="tab">
  <a class="mdui-tab"></a>
</div>
<a class="tab-prev mdui-btn mdui-btn-icon mdui-ripple" href="javascript:void(0)"><i class="mdui-icon material-icons">chevron_left</i></a>
<a class="tab-next mdui-btn mdui-btn-icon mdui-ripple" href="javascript:void(0)"><i class="mdui-icon material-icons">chevron_right</i></a>`
    );

    _this.$tab = _this.$tabWrapper.find('.mdui-tab');
    _this.$tabPrev = _this.$tabWrapper.find('.tab-prev');
    _this.$tabNext = _this.$tabWrapper.find('.tab-next');

    _this.Tab = new mdui.Tab('#tab .mdui-tab');

    _this.$tab.on('change.mdui.tab', function(event) {
      // id为 start、setting 或者 文件sha1
      let fileSha1 = event._detail.id;

      if ($$('#' + fileSha1).data('rendered')) {
        Pubsub.emit('tab-show', event._detail.id);
      }
    });

    _this.articleHeaders = [];
    _this.currentFilesInfo = [];

    // 当前 tab 页数
    _this.pageCurrent = 1;

    $$(window).on('resize', function() {
      _this.updateTabNav();
    });

    $$('#tab .tab-prev').on('click', function() {
      if ($$(this).attr('disabled') === '') {
        return;
      }

      _this.toPrevTabNav();
    });

    $$('#tab .tab-next').on('click', function() {
      if ($$(this).attr('disabled') === '') {
        return;
      }

      _this.toNextTabNav();
    });

    /**
     * 绑定关闭选项卡事件
     * @param $tab
     */
    let bindTabCloseEvent = function($tab) {
      $tab.find('.tab-close').on('click', function() {
        if ($tab.hasClass('mdui-tab-active')) {
           _this.Tab.show($tab.prev().index() - 1);
        }

        let fileSha1 = $tab.attr('href').substr(1);

        $tab.remove();

        if (isArticle(fileSha1)) {
          $$(`#${fileSha1}`).remove();
        } else if (isStart(fileSha1)) {
          $$('#start').hide();
        } else if (isSetting(fileSha1)) {
          $$('#setting').hide();
        }

        _this.Tab.handleUpdate();
        _this.updateTabNav();

        delete _this.currentFilesInfo[fileSha1];
        delete _this.articleHeaders[fileSha1];

        if (!_this.$tab.children('a').length) {
          Pubsub.emit('files-all-closed');
        }

        return false;
      });
    };

    /**
     * 页面滚动时，实时更新目录的锚点
     */
    let onScroll = $$.throttle(function() {
      let $article = $$(this);
      let fileSha1 = $article.attr('id');

      if (!_this.articleHeaders[fileSha1]) {
        return;
      }

      let scrollHeight = $article.get(0).scrollTop;

      $$.each(_this.articleHeaders[fileSha1], function() {
        const $this = $$(this);
        const anchor = $this.attr('id');
        if ($this.get(0).offsetTop - 24 < scrollHeight) {
          Pubsub.emit('article-anchor-change', {
            fileSha1: fileSha1,
            anchor: anchor
          });
          return false;
        }
      });

    }, 100);

    /**
     * 打开文件后渲染文件到页面中
     */
    Pubsub.subscribe('file-opened', (fileInfo) => {
      let fileSha1 = 'id' + Sha1(fileInfo.filePath);

      // 文件未打开时，打开文件
      if (typeof _this.currentFilesInfo[fileSha1] === 'undefined') {
        _this.currentFilesInfo[fileSha1] = fileInfo;

        let $tab = $$(
          `<a href="#${fileSha1}" class="mdui-ripple" data-path="${fileInfo.filePath}" data-name="${fileInfo.fileName}" title="${fileInfo.filePath}">
  <div class="tab-title mdui-text-truncate" style="width: 100%;">${fileInfo.fileName}</div>
  <i class="tab-close mdui-icon material-icons" title="关闭">close</i>
</a>`);
        _this.$tab.append($tab);
        _this.$articleWrapper.append(`<div id="${fileSha1}" class="markdown-body"></div>`);
        bindTabCloseEvent($tab);
        _this.updateTabNav();
        _this.toLastTabNav();
        $$('#' + fileSha1).on('scroll', onScroll);

        _this.Tab.handleUpdate();

        // 渲染文章
        _this.render(fileInfo, fileSha1);

        // 滚动到页面顶部
        scrollTo(0, 0);
      }

      // 切换到该文件
      _this.$tab.children('a').each(function(i) {
        if ($$(this).attr('href') === `#${fileSha1}`) {
          _this.Tab.show(i);
        }
      });
    });

    // 打开开始页面
    Pubsub.subscribe('page-start-open', () => {
      let fileSha1 = 'start';

      // 开始页面未打开时
      if (typeof _this.currentFilesInfo[fileSha1] === 'undefined') {
        _this.currentFilesInfo[fileSha1] = 'start';

        let $tab = $$(
          `<a href="#${fileSha1}" class="mdui-ripple">
  <div class="tab-title mdui-text-truncate" style="width: 100%;">开始使用</div>
  <i class="tab-close mdui-icon material-icons" title="关闭">close</i>
</a>`);
        _this.$tab.append($tab);
        bindTabCloseEvent($tab);
        _this.updateTabNav();
        _this.toLastTabNav();
        _this.Tab.handleUpdate();

        // 滚动到页面顶部
        scrollTo(0, 0);
      }

      // 切换到该页面
      _this.$tab.children('a').each(function(i) {
        if ($$(this).attr('href') === `#${fileSha1}`) {
          _this.Tab.show(i);
        }
      });
    });

    Pubsub.subscribe('page-setting-open', () => {
      let fileSha1 = 'setting';

      // 设置页面未打开时
      if (typeof _this.currentFilesInfo[fileSha1] === 'undefined') {
        _this.currentFilesInfo[fileSha1] = 'setting';

        let $tab = $$(
          `<a href="#${fileSha1}" class="mdui-ripple">
  <div class="tab-title mdui-text-truncate" style="width: 100%;">设置</div>
  <i class="tab-close mdui-icon material-icons" title="关闭">close</i>
</a>`);
        _this.$tab.append($tab);
        bindTabCloseEvent($tab);
        _this.updateTabNav();
        _this.toLastTabNav();
        _this.Tab.handleUpdate();

        // 滚动到页面顶部
        scrollTo(0, 0);
      }

      // 切换到该页面
      _this.$tab.children('a').each(function(i) {
        if ($$(this).attr('href') === `#${fileSha1}`) {
          _this.Tab.show(i);
        }
      });
    });

    /**
     * 流程图主题无法使用 CSS 控制，因此在切换主题后重新渲染流程图
     */
    Pubsub.subscribe('set-theme', (theme) => {
      Flowchart.render(_this.$articleWrapper, theme);
    });

    /**
     * 重新渲染当前打开的文件
     */
    Pubsub.subscribe('re-render-current-files', () => {
      if (Object.keys(_this.currentFilesInfo).length) {
        for (let fileSha1 in _this.currentFilesInfo) {
          if (isArticle(fileSha1)) {
            _this.render(_this.currentFilesInfo[fileSha1], fileSha1);
          }
        }
      }
    });

    /**
     * @param page  start 或 setting
     */
    function pageStartAndSettingOpened(page) {
      let fileSha1 = page;
      let fileName;

      if (page === 'start') {
        fileName = '开始使用';
      }

      if (page === 'setting') {
        fileName = '设置';
      }

      // 页面未打开时，打开页面
      if (typeof _this.currentFilesInfo[fileSha1] === 'undefined') {
        _this.currentFilesInfo[fileSha1] = fileSha1;

        let $tab = $$(
          `<a href="#${fileSha1}" class="mdui-ripple">
  <div class="tab-title mdui-text-truncate" style="width: 100%;">${fileName}</div>
  <i class="tab-close mdui-icon material-icons" title="关闭">close</i>
</a>`);
        _this.$tab.append($tab);
        $$('#' + fileSha1).show();
        bindTabCloseEvent($tab);
        _this.updateTabNav();
        _this.toLastTabNav();
        _this.Tab.handleUpdate();
        scrollTo(0, 0);
      }

      // 切换到该文件
      _this.$tab.children('a').each(function(i) {
        if ($$(this).attr('href') === `#${fileSha1}`) {
          _this.Tab.show(i);
        }
      });
    };

    /**
     * 打开开始页面
     */
    Pubsub.subscribe('start-opened', () => {
      pageStartAndSettingOpened('start');
    });

    /**
     * 打开设置页面
     */
    Pubsub.subscribe('setting-opened', () => {
      pageStartAndSettingOpened('setting');
    });

    /**
     * 滚动文章到指定位置
     */
    Pubsub.subscribe('article-to-anchor', ({fileSha1, anchor}) => {
      let $article = $$('#' + fileSha1);
      $article.get(0).scrollTop = $article.find('#' + anchor).get(0).offsetTop - 16;
    });

    /**
     * 页面内的锚点跳转
     */
    $$(document).on('click', '#article .toc a', function() {
      let $a = $$(this);
      let anchor = $a.data('id');
      let $article = $a.parents('.markdown-body');

      $article.get(0).scrollTop = $article.find('#' + anchor).get(0).offsetTop - 16;
    });
  }

  /**
   * 渲染文件
   * @param fileInfo
   * @param fileSha1
   */
  render(fileInfo, fileSha1) {
    const _this = this;
    const $article = $$('#' + fileSha1);

    let markdownContent = fs.readFileSync(fileInfo.filePath).toString();

    // 是否包含 [TOC]
    let withToc = false;
    if (markdownContent.indexOf('[TOC]') > -1 && State.getConfig('markdownToc')) {
      withToc = true;
      markdownContent = markdownContent.replace('[TOC]', `<div id="markdown-toc-${fileSha1}"></div>`);
    }

    // HTML
    let HTMLContent = Markdown.render(markdownContent);

    $article.html(HTMLContent).data('rendered', true);

    _this.articleHeaders[fileSha1] = $article.find('h1, h2, h3, h4, h5, h6').get().reverse();


    // 生成 TOC，替换 [TOC]
    if (withToc && State.getConfig('markdownToc')) {
      new Toc(fileSha1, {
        'level': 6,
        'class': 'toc',
        'top': -1,
        'targetId': 'markdown-toc-' + fileSha1
      });
    }

    setTimeout(function() {
      if (State.getConfig('markdownCodeLine')) {
        CodeLine.render($article);
      }

      if (State.getConfig('markdownFlowchart')) {
        Flowchart.render($article);
      }

      if (State.getConfig('markdownSequenceDiagrams')) {
        SequenceDiagrams.render($article);
      }

      if (State.getConfig('markdownKatex')) {
        Katex.render($article);
      }
    }, 0);

    // 文章渲染完成
    Pubsub.emit('article-rendered', fileSha1);
  }

  /**
   * 更新 tab 左右按钮显示状态，根据当前激活的标签页进行滚动，激活的标签页始终显示
   */
  updateTabNav() {
    const _this = this;

    _this.tabWrapperWidth = _this.$tabWrapper.find('.tab').width();
    _this.tabWidth = _this.$tab.width();
    _this.pageTotal = Math.ceil(_this.tabWidth / _this.tabWrapperWidth);

    if (_this.pageTotal <= 1 && _this.$tab.css('transform') === 'matrix(1, 0, 0, 1, 0, 0)"') {
      _this.$tabPrev.hide();
      _this.$tabNext.hide();
      return;
    }

    _this.$tabPrev.show();
    _this.$tabNext.show();

    if (_this.pageCurrent > 1) {
      _this.$tabPrev.removeAttr('disabled');
    } else {
      _this.$tabPrev.attr('disabled', '');
    }

    if (_this.pageCurrent < _this.pageTotal) {
      _this.$tabNext.removeAttr('disabled');
    } else {
      _this.$tabNext.attr('disabled', '');
    }
  }

  /**
   * 滚动到 tab 下一页
   */
  toNextTabNav() {
    const _this = this;

    _this.pageCurrent++;

    let left;

    if (_this.pageCurrent === _this.pageTotal) {
      let lastPageWidth = _this.tabWidth % _this.tabWrapperWidth;
      left = (_this.pageCurrent - 2) * _this.tabWrapperWidth + lastPageWidth;
    } else {
      left = (_this.pageCurrent - 1) * _this.tabWrapperWidth;
    }

    _this.$tab.css({
      'transform': `translateX(-${left}px)`
    });


    _this.updateTabNav();
  }

  /**
   * 滚动到 tab 上一页
   */
  toPrevTabNav() {
    const _this = this;

    _this.pageCurrent--;

    let left = (_this.pageCurrent - 1) * _this.tabWrapperWidth;
    _this.$tab.css({
      'transform': `translateX(-${left}px)`
    });

    _this.updateTabNav();
  }

  /**
   * 滚动到 tab 最后一页
   */
  toLastTabNav() {
    const _this = this;

    _this.pageCurrent = _this.pageTotal;

    let lastPageWidth = _this.tabWidth % _this.tabWrapperWidth;
    let left = (_this.pageCurrent - 2) * _this.tabWrapperWidth + lastPageWidth;

    if (!isNaN(left)) {
      _this.$tab.css({
        'transform': `translateX(-${left}px)`
      });
    }

    _this.updateTabNav();
  }

  /**
   * 滚动到 tab 第一页
   */
  toFirstTabNav() {
    const _this = this;

    _this.pageCurrent = 1;

    let left = 0;
    _this.$tab.css({
      'transform': `translateX(-${left}px)`
    });

    _this.updateTabNav();
  }
}

export default Page;